package miage.rest.resource;

import java.io.FileInputStream;
import miage.rest.Application;

import miage.rest.db.Database;
import miage.rest.routing.UriTemplateFinder;
import miage.rest.test.Configuration;

import org.apache.commons.dbcp.BasicDataSource;

import org.custommonkey.xmlunit.XMLUnit;

import org.dbunit.DatabaseTestCase;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.ext.mysql.MySqlConnection;
import org.dbunit.operation.CompositeOperation;
import org.dbunit.operation.DatabaseOperation;

import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.ServerResource;
import org.restlet.routing.Router;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

/**
 *
 * @author Schwartz Michaël
 */
public abstract class ResourceTestCase<T extends ServerResource> extends DatabaseTestCase {
	private Database database;
	private Application application;

	abstract protected T createResource();

	public T newResourceInstance() {
		T resource = createResource();

		return resource;
	}

	public Representation handleResource() {
		return handleResource(new Request());
	}

	public Representation handleResource(Request request) {
		return handleResource(request, new Response(request), Method.GET);
	}

	public Representation handleResource(Request request, Method method) {
		return handleResource(request, new Response(request), method);
	}


	public Representation handleResource(Request request, Response response) {
		return handleResource(request, response, Method.GET);
	}

	public Representation handleResource(Request request, Response response, Method method) {
		Representation result = null;
		T resource = newResourceInstance();

		request.setMethod(method);

		resource.init(getApplication().getContext(), request, response);

		if ((response == null) || response.getStatus().equals(Status.SUCCESS_OK)) {
			result = resource.handle();
		}

		resource.release();

		return result;
	}

	@Override
	protected IDatabaseConnection getConnection() throws Exception {
		return new MySqlConnection(getDatabase().getNewConnection(),null);
	}

	@Override
	protected IDataSet getDataSet() throws Exception {
		return new FlatXmlDataSetBuilder()
					.setColumnSensing(true)
					.build(new FileInputStream("data/" + getClass().getSimpleName() + ".xml"));
	}

	/**
     * Returns the database operation executed in test setup.
     */
	@Override
    protected DatabaseOperation getSetUpOperation() throws Exception {
        return new CompositeOperation(DatabaseOperation.TRUNCATE_TABLE, DatabaseOperation.INSERT);
    }


	protected Configuration getConfiguration() {
		Configuration config = new Configuration();


		return config;
	}

	public final Database getDatabase() {
		if (this.database == null) {

			Configuration config = getConfiguration();
			BasicDataSource ds = new BasicDataSource();

			ds.setDriverClassName(config.getDbDriverClassName());
			ds.setUrl(config.getDbUrl());
			ds.setUsername(config.getDbUser());
			ds.setPassword(config.getDbPassword());

			this.database = new Database(ds);
		}

		return this.database;
	}

	public Application getApplication() {
		if (application == null) {
			Router router = new Router();
			application = new Application(router);
		}

		return application;
	}

	public UriTemplateFinder getUriTemplateFinder() {
		Restlet inboundRoot = getApplication().createInboundRoot();
		UriTemplateFinder uriTemplateFinder = null;
		if (inboundRoot instanceof Router) {
			uriTemplateFinder = new UriTemplateFinder((Router) inboundRoot);
		} else {
			uriTemplateFinder = new UriTemplateFinder(new Router());
		}

		return uriTemplateFinder;
	}

	public Document getTestableDocument(Representation representation) {
		assertIsXml(representation);
		
		Document document = null;
		try {
			InputSource inputSource = new InputSource(representation.getReader());
			
			document = XMLUnit.buildControlDocument(inputSource);
		} catch (Exception ex) {
			fail("Impossible de créer le document xml à partir de la représentation");
		}

		return document;
	}

	public void assertIsXml(Representation representation) {
		assertTrue(representation.getMediaType().equals(MediaType.TEXT_XML));
	}

	
}
